#library('assembly-debugger');

#import('dart:html');

#source('engine.dart');
#source('memory.dart');

// TODO: types
// TODO: cache document.queryAll results

class AssemblyDebugger {
  final String tab_ = '  ';
  
  String current_asm_ = '6502';
  
  Map labels_ = {};
  List lines_ = [];

  Engine engine_;
  Memory memory_;

  AssemblyDebugger()
      : engine_ = new Engine(),
        memory_ = new Memory() {
    SelectElement asm_select = document.queryAll('#asm_select');
    for (var key in Engine.asm) {
      OptionElement = document.createElement('option');
      option.value = key;
      option.appendChild(document.createTextNode('key'));
      if (key === current_asm_)
        option.selected = 'selected';
      asm_select.appendChild(option);
    }
    asm_select.on.change = onAsmChanged();

    TextAreaElement code_entry = document.queryAll('#code_entry');
    code_entry.on.keyDown = checkTab;
    code_entry.innerText = 'LDX #00\nLDY #00\n.outer\n.inner\nTXA\nSTA ($00,x)\nINX\nCPX #FF\nBNE inner\nLDX #00\nINY\nCPY #FF\nBNE outer\n';

    document.queryAll('#run_to_start_button').on.click = onRunToStartClick();
    document.queryAll('#continue_button').on.click = onContinueClick();
    document.queryAll('#pause_button').on.click = onPauseClick();
    document.queryAll('#step_button').on.click = onStepClick();
    document.queryAll('#stop_button').on.click = onStopClick();

    /*
    // LSR and addressing test
    LDX #2F
    STX $1234
    LDX #12
    LDY #31
    STX $2A
    STY $2B
    LDY #03
    LSR ($2A),Y
    LDA $1234
    */
    rebuildPage();
  }

  void rebuildPage() {
    engine_.initialize(current_asm_, document.queryAll('#registers'));

    // TODO: warn before clearing text
    // var code_entry = document.queryAll('#code_entry');
    // code_entry.innerText = '';

    memory_.initialize(document.queryAll('#memory_text'),
                       document.queryAll('#memory_video'));
  }

  String get selectedAsm() {
    SelectElement asm_select = document.queryAll('#asm_select');
    return asm_select.options[asm_select.selectedIndex].value;
  }

  void onAsmChanged() {
    String selected_asm = selectedAsm;
    if (selected_asm !== current_asm_) {
      current_asm_ = selected_asm;
      rebuildPage();
    }
  }

  void onRunToStartClick() {
    rebuildPage();
    List<String> code = document.queryAll('#code_entry').value.split('\n');
    engine_.runToStart(code);

    // TODO: edit and continue
    document.queryAll('#code_entry').readonly = 'readonly';
    document.queryAll('#run_to_start_button').disabled = 'disabled';
    document.queryAll('#pause_button').disabled = 'disabled';
    document.queryAll('#continue_button').disabled = '';
    document.queryAll('#step_button').disabled = '';
    document.queryAll('#stop_button').disabled = '';
  }

  void onContinueClick() {
    if (engine_.run() === -1) {
      document.queryAll('#code_entry').readonly = '';
      document.queryAll('#run_to_start_button').disabled = '';
      document.queryAll('#pause_button').disabled = 'disabled';
      document.queryAll('#stop_button').disabled = 'disabled';
    } else {
      document.queryAll('#code_entry').readonly = 'readonly';
      document.queryAll('#run_to_start_button').disabled = 'disabled';
      document.queryAll('#pause_button').disabled = '';
      document.queryAll('#stop_button').disabled = '';
    }
    document.queryAll('#continue_button').disabled = 'disabled';
    document.queryAll('#step_button').disabled = 'disabled';
  }

  void onPauseClick() {
    engine_.pause();
    document.queryAll('#code_entry').readonly = 'readonly';
    document.queryAll('#run_to_start_button').disabled = 'disabled';
    document.queryAll('#pause_button').disabled = 'disabled';
    document.queryAll('#continue_button').disabled = '';
    document.queryAll('#step_button').disabled = '';
    document.queryAll('#stop_button').disabled = '';
  }

  void onStepClick() {
    if (engine_.step() === -1) {
      document.queryAll('#code_entry').readonly = '';
      document.queryAll('#run_to_start_button').disabled = '';
      document.queryAll('#continue_button').disabled = 'disabled';
      document.queryAll('#step_button').disabled = 'disabled';
      document.queryAll('#stop_button').disabled = 'disabled';
    } else {
      document.queryAll('#code_entry').readonly = 'readonly';
      document.queryAll('#run_to_start_button').disabled = 'disabled';
      document.queryAll('#continue_button').disabled = '';
      document.queryAll('#step_button').disabled = '';
      document.queryAll('#stop_button').disabled = '';
    }
    document.queryAll('#pause_button').disabled = 'disabled';
  }

  void onStopClick() {
    engine_.reset();
    document.queryAll('#code_entry').readonly = '';
    document.queryAll('#run_to_start_button').disabled = '';
    document.queryAll('#pause_button').disabled = 'disabled';
    document.queryAll('#continue_button').disabled = 'disabled';
    document.queryAll('#step_button').disabled = 'disabled';
    document.queryAll('#stop_button').disabled = 'disabled';
  }

  void checkTab(e) {
    var t = e.target;
    var ss = t.selectionStart;
    var se = t.selectionEnd;

    if (e.keyCode === 9) {
      e.preventDefault();

      if (ss != se && t.value.slice(ss, se).indexOf('\n') != -1) {
        var pre = t.value.slice(0, ss);
        var sel = t.value.slice(ss, se).replace('/\n/g', '\n' + tab_);
        var post = t.value.slice(se, t.value.length);

        t.value = pre.concat(tab).concat(sel).concat(post);

        t.selectionStart = ss + tab.length;
        t.selectionEnd = se + tab.length;
      } else {
        t.value = t.value.slice(0, ss).concat(tab).concat(t.value.slice(ss, t.value.length));
        if (ss === se) {
          t.selectionStart = t.selectionEnd = ss + tab_.length;
        } else {
          t.selectionStart = ss + tab_.length;
          t.selectionEnd = se + tab_.length;
        }
      }
    }
  }
}

void main() {
  return new AssemblyDebugger().run();
}
